<?
    final class Principio_Model_SpaMapper extends Principio_Mapper
    {
        protected static $db_table = null;
        protected static function getDbTableName() { return "Spa"; }



        const PRV_ATTEMPT = 0;
        const PRV_XML_FAIL = 1;
        const PRV_OK = 2;
        const PRV_FIRMWARE_LOOKUP = 3;
        const PRV_FIRMWARE_FAIL = 4;
        const PRV_FIRMWARE_OK = 5;
        const PRV_FIRMWARE_NOT_USED = 6;


        public static function delete(Principio_Model_Spa $model_spa, $use_transaction = true, $check_last = false)
        {
            try
            {
                if ($use_transaction)
                    self::getDBTable()->getAdapter()->beginTransaction();

                // Delete AccountLink
                foreach ($model_spa->getAccountLinkCollection() as $model_account_link)
                    $model_account_link->delete();

                // Delete SPA Ext Templates
                $model_spa->deleteTemplates();

                // Check if it is a last SPA with current type
                if ($check_last)
                {
                    if ($model_spa->getModelTypeInCompany()->getSpaCollection()->count() == 1)
                        $model_spa->getModelTypeInCompany()->delete(false);
                };

                // Delete SPA
                self::getDBTable()->delete(['id=?' => $model_spa->getID()]);

                if ($use_transaction)
                    self::getDBTable()->getAdapter()->commit();

                return true;
            }
            catch (Exception $ex)
            {
                $return = self::reportException($ex);

                if ($use_transaction)
                {
                    self::getDBTable()->getAdapter()->rollback();
                    return false;
                }
                else
                    return $return;

            };
        }


        public static function save(Principio_Model_Spa $model_spa)
        {
            try
            {
                self::getDBTable()->getAdapter()->beginTransaction();

                $data = [
                    'mac' => $model_spa->getMAC(),
                    'serial' => $model_spa->getSerial(),
                    'ip' => $model_spa->getIP()
                ];

                if ($model_spa->getID() == -1)
                {
                    $data['company_id'] = $model_spa->getModelCompany()->getID();
                    $data['type_id'] = $model_spa->getModelType()->getID();

                    // Check if it is first SPA of its type
                    if ($model_spa->getModelCompany()->getModelTypeInCompany($model_spa->getModelType()) === false)
                    {
                        // create templates in that case
                        $model_type_in_company = new Principio_Model_TypeInCompany($model_spa->getModelCompany(), $model_spa->getModelType());
                        $model_type_in_company->add();
                    };

                    $model_spa->setID(self::getDBTable()->insert($data));

                    // Create AccountLink
                    foreach ($model_spa->getAccountLinkCollection() as $model_acount_link)
                        $model_acount_link->add();

                    $model_spa->addTemplates();
                }
                else
                {
                    self::getDBTable()->update($data, ['id=?' => $model_spa->getID()]);

                    foreach ($model_spa->getAccountLinkCollection() as $model_acount_link)
                        $model_acount_link->save();
                };

                self::getDBTable()->getAdapter()->commit();
                return true;
            }
            catch (Exception $ex)
            {
                self::getDBTable()->getAdapter()->rollback();
                return self::reportException($ex);
            };
        }


        public static function fetch($id)
        {
            try
            {
                $spa_raw = self::getDBTable()->find(intval($id));
                return is_null($spa_raw) ? false : Principio_Model_Spa::fromArray($spa_raw[0]->toArray());
            }
            catch (Exception $ex)
            {
                return self::reportException($ex);
            };
        }


        public static function fetchForPrv($IP, $MAC, $serial)
        {
            try
            {
                $select = self::getDBTable()->select()->where("ip=?", $IP)->where("mac=?", $MAC)->where("serial=?", $serial);
                $spa_raw = self::getDBTable()->fetchRow($select);

                if (is_null($spa_raw))
                    return false;
                else
                    return Principio_Model_Spa::fromArray($spa_raw->toArray());

            }
            catch (Exception $ex)
            {
                return self::reportException($ex);
            };
        }


        public static function getByTypeInCompany(Principio_Model_TypeInCompany $model_type_in_company)
        {
            try
            {
                $select = self::getDBTable()->select()->order(["ip DESC"])->where("type_id=?", $model_type_in_company->getModelType()->getID())->where("company_id=?", $model_type_in_company->getModelCompany()->getID());
                $values = self::getDBTable()->fetchAll($select);

                return Principio_Model_Spa::makeCollectionFromTypeInCompany($model_type_in_company, $values->toArray());
            }
            catch (Exception $ex)
            {
                return self::reportException($ex);
            };
        }


        public static function getIpInUse(Principio_Model_Company_Abstract $model_company_abstract, $cur_ip = null)
        {
            try
            {
                $select = self::getDBTable()->select()->where("company_id=?", $model_company_abstract->getID());
                if (!is_null($cur_ip))
                    $select = $select->where("ip<>?", $cur_ip);

                return (self::getDBTable()->fetchAll($select)->toArray());
            }
            catch (Exception $ex)
            {
                return self::reportException($ex);
            };
        }


        public static function getIpNotInUse(Principio_Model_Company_Abstract $model_company_abstract, $cur_ip = null)
        {
            $ip_in_use = array();

            if (($model_company_abstract->isCompanyInPool()) || ($model_company_abstract->isPool()))
            {
                if ($model_company_abstract->isCompanyInPool())
                    $model_company_abstract = $model_company_abstract->getModelPool();

                foreach ($model_company_abstract->getCompanies() as $model_company)
                    $ip_in_use = array_merge($ip_in_use, self::getIpInUse($model_company, $cur_ip));
            };

            $ip_in_use = array_merge($ip_in_use, self::getIpInUse($model_company_abstract, $cur_ip));

            $ip_in_use_long = array();
            foreach ($ip_in_use as $index => $ip)
                $ip_in_use_long[] = ip2long($ip['ip']);

            $ip_range_from_long = ip2long($model_company_abstract->getRangeFrom());
            $ip_range_to_long = ip2long($model_company_abstract->getRangeTo());

            $ip_not_in_use = array();

            $i = $ip_range_from_long;
            sort($ip_in_use_long);
            $k = 0;
            $p = 0;

            while ($i <= $ip_range_to_long)
            {
                if ($k < count($ip_in_use_long))
                    $p = $ip_in_use_long[$k++];
                else
                    $p = $ip_range_to_long + 1;

                while ($i < $p)
                {
                    $ip_not_in_use[] = long2ip($i);
                    $i++;
                };

                $i++;
            };

            return $ip_not_in_use;
        }


        public static function checkUnique(&$values, $field)
        {
            try
            {
                $select = self::getDBTable()->select()->where($field."=?", $values[$field])->where("id<>?", $values['id']);
                $result = self::getDBTable()->fetchAll($select);

                return (count($result) != 0) ? (Principio_Model_Company_AbstractMapper::fetch($result[0]['company_id'])) : false;
            }
            catch (Exception $ex)
            {
                return self::reportException($ex);
            };
        }


        // TODO - delete, only in DHCP
        public static function getInCompany($company_id)
        {
            try
            {
                $select = self::getDBTable()->select()->where("company_id=?", $company_id);
                $spaes = self::getDBTable()->fetchAll($select);

                $spa_array = array();
                foreach ($spaes as $spa)
                    $spa_array[] = self::get($spa->id);

                return $spa_array;
            }
            catch (Exception $ex)
            {
                return self::reportException($ex);
            };
        }


        public static function logProvisioning(Principio_Model_Spa $model_spa, $type)
        {
            switch ($type)
            {
                case self::PRV_ATTEMPT:
                    $data = array("last_prov_attempt" => new Zend_Db_Expr("NOW()"), "prov_status" => "Profile: generating");
                    break;

                case self::PRV_XML_FAIL:
                    $data = array("prov_status" => "Profile: FAIL", "last_prov_msg" => "Can't generate profile");
                    break;

                case self::PRV_OK:
                    $data = array("last_prov" => new Zend_Db_Expr("NOW()"), "prov_status" => "Profile: was sent", "last_prov_msg" => "Ok");
                    break;

                case self::PRV_FIRMWARE_LOOKUP:
                    $data = array("prov_status" => "Firmware: looking for firmware");
                    break;

                case self::PRV_FIRMWARE_FAIL:
                    $data = array("last_firmware" => "0 (ERROR)", "prov_status" => "Firmware: FAIL", "last_prov_msg" => "Requested fw [".$model_spa->getModelType()->getModelFirmware()->getCaption()."] wasn't found");
                    break;

                case self::PRV_FIRMWARE_OK:
                    $data = array("last_firmware" => $model_spa->getModelType()->getModelFirmware()->getCaption(), "prov_status" => "Firmware: was sent", "last_prov_msg" => "Ok");
                    break;

                case self::PRV_FIRMWARE_NOT_USED:
                    $data = array("prov_status" => "Firmware: requested, but not used", "last_prov_msg" => "Fail");
                    break;

                default:
                    $data = array();
                    break;
            };

            self::getDBTable()->update($data, ['id=?' => $model_spa->getID()]);
        }

        /*
        public static function search($string)
        {
            $search_fields = array(
                "mac" => "Mac",
                "serial" => "Serial number",
                "ip" => "IP"
            );
            $result = parent::searchInDB(self::getDBTable(), $search_fields, $string);
            foreach ($result as $res)
            {
                $model_search = new Principio_Model_Search($string, "Spa");
                $menu_data = array("menu_name" => "view_by_company", "level" => EXPAND_VIEW_BY_COMPANY, "type_id" => $res["type_id"], "company_id" => $res["company_id"], "open_level" => 2);
                $model_search->setId($res["id"])->setResultName($res["ip"]." [".$res["mac"]."]")->setOpenItemFunctionName("Spa")->setParentID(false)->setMenuData($menu_data);
                foreach ($res as $col_name => $value)
                {
                    if (strstr($value, $string) && in_array($col_name, array_keys($search_fields)))
                        $searchable_text[$search_fields[$col_name]] = $value;
                }
                $model_search->setResult($searchable_text);
                $search[$res["id"]] = $model_search;
            }
            return $search;
        }
        */
    }
?>